package com.wechat.service.impl;

import com.wechat.entity.config.AppConfig;
import com.wechat.entity.constants.Constants;
import com.wechat.entity.dto.MessageSendDto;
import com.wechat.entity.dto.SysSettingDto;
import com.wechat.entity.dto.TokenUserInfoDto;
import com.wechat.entity.enums.*;
import com.wechat.entity.po.*;
import com.wechat.entity.query.*;
import com.wechat.entity.vo.PaginationResultVO;
import com.wechat.exception.BusinessException;
import com.wechat.mappers.*;
import com.wechat.redis.RedisComponent;
//import com.wechat.service.ChatSessionUserService;
import com.wechat.service.ChatSessionUserService;
import com.wechat.service.GroupInfoService;
import com.wechat.service.UserContactService;
import com.wechat.utils.StringTools;
import com.wechat.websocket.ChannelContextUtils;
import com.wechat.websocket.MessageHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;


/**
 * 业务接口实现
 */
@Service("groupInfoService")
public class GroupInfoServiceImpl implements GroupInfoService {

    private static final Logger logger = LoggerFactory.getLogger(GroupInfoServiceImpl.class);

    @Resource
    private AppConfig appConfig;

    @Resource
    private GroupInfoMapper<GroupInfo, GroupInfoQuery> groupInfoMapper;

    @Resource
    private RedisComponent redisComponent;

    @Resource
    private UserContactMapper<UserContact, UserContactQuery> userContactMapper;

    @Resource
    private ChatSessionUserService chatSessionUserService;

    @Resource
    private ChatSessionMapper<ChatSession, ChatSessionQuery> chatSessionMapper;

    @Resource
    private ChatSessionUserMapper chatSessionUserMapper;

    @Resource
    private MessageHandler messageHandler;

    @Resource
    private ChannelContextUtils channelContextUtils;

    @Resource
    private ChatMessageMapper<ChatMessage, ChatMessageQuery> chatMessageMapper;

    @Resource
    private UserInfoMapper<UserInfo, UserInfoQuery> userInfoMapper;

    @Resource
    private UserContactService userContactService;

    @Resource
    @Lazy//循环依赖
    private GroupInfoService groupInfoService;

    /**
     * 根据条件查询列表
     */
    @Override
    public List<GroupInfo> findListByParam(GroupInfoQuery param) {
        return this.groupInfoMapper.selectList(param);
    }

    /**
     * 根据条件查询列表
     */
    @Override
    public Integer findCountByParam(GroupInfoQuery param) {
        return this.groupInfoMapper.selectCount(param);
    }

    /**
     * 分页查询方法
     */
    @Override
    public PaginationResultVO<GroupInfo> findListByPage(GroupInfoQuery param) {
        int count = this.findCountByParam(param);
        int pageSize = param.getPageSize() == null ? PageSize.SIZE15.getSize() : param.getPageSize();

        SimplePage page = new SimplePage(param.getPageNo(), count, pageSize);
        param.setSimplePage(page);
        List<GroupInfo> list = this.findListByParam(param);
        PaginationResultVO<GroupInfo> result = new PaginationResultVO(count, page.getPageSize(), page.getPageNo(), page.getPageTotal(), list);
        return result;
    }

    /**
     * 新增
     */
    @Override
    public Integer add(GroupInfo bean) {
        return this.groupInfoMapper.insert(bean);
    }

    /**
     * 批量新增
     */
    @Override
    public Integer addBatch(List<GroupInfo> listBean) {
        if (listBean == null || listBean.isEmpty()) {
            return 0;
        }
        return this.groupInfoMapper.insertBatch(listBean);
    }

    /**
     * 批量新增或者修改
     */
    @Override
    public Integer addOrUpdateBatch(List<GroupInfo> listBean) {
        if (listBean == null || listBean.isEmpty()) {
            return 0;
        }
        return this.groupInfoMapper.insertOrUpdateBatch(listBean);
    }

    /**
     * 多条件更新
     */
    @Override
    public Integer updateByParam(GroupInfo bean, GroupInfoQuery param) {
        StringTools.checkParam(param);
        return this.groupInfoMapper.updateByParam(bean, param);
    }

    /**
     * 多条件删除
     */
    @Override
    public Integer deleteByParam(GroupInfoQuery param) {
        StringTools.checkParam(param);
        return this.groupInfoMapper.deleteByParam(param);
    }

    /**
     * 根据GroupId获取对象
     */
    @Override
    public GroupInfo getGroupInfoByGroupId(String groupId) {
        return this.groupInfoMapper.selectByGroupId(groupId);
    }

    /**
     * 根据GroupId修改
     */
    @Override
    public Integer updateGroupInfoByGroupId(GroupInfo bean, String groupId) {
        return this.groupInfoMapper.updateByGroupId(bean, groupId);
    }

    /**
     * 根据GroupId删除
     */
    @Override
    public Integer deleteGroupInfoByGroupId(String groupId) {
        return this.groupInfoMapper.deleteByGroupId(groupId);
    }

    /**
     * 更新/创建群组
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveGroup(GroupInfo groupInfo, MultipartFile avatarFile, MultipartFile avatarCover) throws IOException {
        Date currentDate = new Date();
        //1.判断群组id是否为空
        if(StringTools.isEmpty(groupInfo.getGroupId())){
            //1.1 空---新增
            GroupInfoQuery groupInfoQuery = new GroupInfoQuery();
            groupInfoQuery.setGroupOwnerId(groupInfo.getGroupOwnerId());
            //1.1.1 判断当前用户创建群聊数量是否超过最大数量
            Integer count = groupInfoMapper.selectCount(groupInfoQuery);
            SysSettingDto sysSettingDto = redisComponent.getSysSetting();
            if(count >= sysSettingDto.getMaxGroupCount()){
                throw new BusinessException("最多支持创建+"+sysSettingDto.getMaxGroupCount()+"个群聊");
            }
            if(null == avatarFile){
                throw new BusinessException("请上传群组头像");
            }

            groupInfo.setCreateTime(currentDate);
            groupInfo.setGroupId(StringTools.getGroupId());
            groupInfoMapper.insert(groupInfo);

            //将群组添加为联系人
            UserContact userContact = UserContact.builder()
                    .userId(groupInfo.getGroupOwnerId())
                    .contactId(groupInfo.getGroupId())
                    .contactType(UserContactTypeEnum.GROUP.getType())
                    .status(UserContactStatusEnum.FRIEND.getStatus())
                    .createTime(currentDate)
                    .lastUpdateTime(currentDate)
                    .build();
            userContactMapper.insert(userContact);

            //创建会话
            String sessionId = StringTools.getChatSessionId4Group(groupInfo.getGroupId());
            ChatSession chatSession = ChatSession.builder()
                    .sessionId(sessionId)
                    .lastMessage(MessageTypeEnum.GROUP_CREATE.getInitMessage())
                    .lastReceiveTime(currentDate.getTime())
                    .build();
            chatSessionMapper.insert(chatSession);

            ChatSessionUser chatSessionUser = new ChatSessionUser();
            chatSessionUser.setSessionId(sessionId);
            chatSessionUser.setUserId(groupInfo.getGroupOwnerId());
            chatSessionUser.setContactId(groupInfo.getGroupId());
            chatSessionUser.setContactName(groupInfo.getGroupName());
            chatSessionUserMapper.insert(chatSessionUser);

            //创建消息
            ChatMessage chatMessage = ChatMessage.builder()
                    .sessionId(sessionId)
                    .contactId(groupInfo.getGroupId())
                    .contactType(UserContactTypeEnum.GROUP.getType())
                    .messageType(MessageTypeEnum.GROUP_CREATE.getType())
                    .messageContent(MessageTypeEnum.GROUP_CREATE.getInitMessage())
                    .status(MessageStatusEnum.SENDED.getStatus())
                    .sendTime(currentDate.getTime())
                    .build();
            chatMessageMapper.insert(chatMessage);

            //将群组添加到联系人
            redisComponent.addUserContact(groupInfo.getGroupOwnerId(),groupInfo.getGroupId());
            //把群channel与用户关联
            channelContextUtils.addUser2Group(groupInfo.getGroupOwnerId(),groupInfo.getGroupId());

            //发送ws消息
            chatSessionUser.setLastMessage(MessageTypeEnum.GROUP_CREATE.getInitMessage());
            chatSessionUser.setLastReceiveTime(currentDate.getTime());
            chatSessionUser.setMemberCount(1);

            MessageSendDto messageSendDto =  new MessageSendDto();
            BeanUtils.copyProperties(chatSessionUser,messageSendDto);
            messageSendDto.setExtendData(chatSessionUser);
            messageHandler.sendMessage(messageSendDto);
        }else{
            //1.2 非空---更新数据
            //1.2.1 判断当前用户是否是群主
            GroupInfo dbgroupInfo = groupInfoMapper.selectByGroupId(groupInfo.getGroupId());
            String dbGroupOwnerId = dbgroupInfo.getGroupOwnerId();
            if(!dbGroupOwnerId.equals(groupInfo.getGroupOwnerId())){//不是群主
                throw new BusinessException(ResponseCodeEnum.CODE_600);
            }
            groupInfoMapper.updateByGroupId(groupInfo,groupInfo.getGroupId());

            //更新群昵称
            String contactNameUpdate = null;//群昵称
            if(!dbgroupInfo.getGroupName().equals(groupInfo.getGroupName())){
                contactNameUpdate = groupInfo.getGroupName();

            }
            chatSessionUserService.updateRedundanceInfo(contactNameUpdate,groupInfo.getGroupId());


            //2. 头像上传
            if(null == avatarFile){
                return;
            }
            String baseFolder = appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE;//获取存放资源的文件路径
            File targetFileFolder = new File(baseFolder + Constants.FILE_FOLDER_AVATAR_NAME);//存放头像的文件夹
            if (!targetFileFolder.exists()) {
                targetFileFolder.mkdirs();
            }
            String filePath = targetFileFolder.getPath() + "/" + groupInfo.getGroupId() + Constants.IMAGE_SUFFIX;//创建头像文件路径
            avatarFile.transferTo(new File(filePath));//保存头像到指定路径
            avatarCover.transferTo(new File(filePath + Constants.COVER_IMAGE_SUFFIX));//保存缩略图头像到指定路径

        }

    }

    /**
     * 解散群组
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void dissolutionGroup(String userId, String groupId) {
        GroupInfo groupInfo = groupInfoMapper.selectByGroupId(groupId);
        if (null == groupInfo || !groupInfo.getGroupOwnerId().equals(userId)) {
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
        //1. 解散群组
        GroupInfo updateGroupInfo = new GroupInfo();
        updateGroupInfo.setStatus(GroupStatusEnum.DISSOLUTION.getStatus());
        groupInfoMapper.updateByGroupId(updateGroupInfo, groupId);

        //2. 删除群成员---更新联系人的信息
        //设置查询条件
        UserContactQuery userContactQuery = new UserContactQuery();
        userContactQuery.setContactId(groupId);
        userContactQuery.setContactType(UserContactTypeEnum.GROUP.getType());
        //执行更新逻辑
        UserContact userContact = new UserContact();
        userContact.setStatus(UserContactStatusEnum.DEL.getStatus());
        userContactMapper.updateByParam(userContact, userContactQuery);

        //在群员联系人列表中删除群组 移除相关群员的联系热缓存
        List<UserContact> contactList = userContactMapper.selectList(userContactQuery);
        for (UserContact contact : contactList) {
            redisComponent.removeUserContact(contact.getUserId(),contact.getContactId());
        }

        String sessionId = StringTools.getChatSessionId4Group(groupId);//获取群会话id
        Date currentDate = new Date();

        //发送通知： 1.更新会话信息 2.记录群消息 3.发送解散通知
        String messageContent = MessageTypeEnum.DISSOLUTION_GROUP.getInitMessage();
        ChatSession chatSession = new ChatSession();
        chatSession.setLastMessage(messageContent);
        chatSession.setLastReceiveTime(currentDate.getTime());
        chatSessionMapper.updateBySessionId(chatSession, sessionId);

        ChatMessage chatMessage = ChatMessage.builder()
                .sessionId(sessionId)
                .contactId(groupId)
                .contactType(UserContactTypeEnum.GROUP.getType())
                .messageType(MessageTypeEnum.DISSOLUTION_GROUP.getType())
                .messageContent(messageContent)
                .sendTime(currentDate.getTime())
                .status(MessageStatusEnum.SENDED.getStatus())
                .build();
        chatMessageMapper.insert(chatMessage);

        MessageSendDto messageSendDto = new MessageSendDto();
        BeanUtils.copyProperties(chatMessage,messageSendDto);

        messageHandler.sendMessage(messageSendDto);

    }

    /**
     * 退出群组
     * @param userId
     * @param groupId
     * @param messageTypeEnum---退出类型：1.主动退出 2.被管理员移除
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void leaveGroup(String userId, String groupId, MessageTypeEnum messageTypeEnum) {
        GroupInfo groupInfo = groupInfoMapper.selectByGroupId(groupId);
        if(groupInfo == null){
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
        if(userId.equals(groupInfo.getGroupOwnerId())){
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
        Integer count = userContactMapper.deleteByUserIdAndContactId(userId, groupId);
        if(count == 0){//删除失败
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
        UserInfo userInfo = userInfoMapper.selectByUserId(userId);

        String sessionId = StringTools.getChatSessionId4Group(groupId);
        Date currentDate = new Date();
        String messageContent = String.format(messageTypeEnum.getInitMessage(),userInfo.getNickName());

        ChatSession chatSession = new ChatSession();
        chatSession.setLastReceiveTime(currentDate.getTime());
        chatSession.setLastMessage(messageContent);
        chatSessionMapper.updateBySessionId(chatSession, sessionId);

        ChatMessage chatMessage = ChatMessage.builder()
                .sessionId(sessionId)
                .contactId(groupId)
                .contactType(UserContactTypeEnum.GROUP.getType())
                .messageType(messageTypeEnum.getType())
                .messageContent(messageContent)
                .sendTime(currentDate.getTime())
                .status(MessageStatusEnum.SENDED.getStatus())
                .build();
        chatMessageMapper.insert(chatMessage);

        UserContactQuery userContactQuery = new UserContactQuery();
        userContactQuery.setContactId(groupId);
        userContactQuery.setStatus(UserContactStatusEnum.FRIEND.getStatus());
        Integer memberCount = userContactMapper.selectCount(userContactQuery);

        MessageSendDto messageSendDto = new MessageSendDto();
        BeanUtils.copyProperties(chatMessage,messageSendDto);
        messageSendDto.setMemberCount(memberCount);
        messageSendDto.setExtendData(userId);
        messageHandler.sendMessage(messageSendDto);
    }

    /**
     * 添加或移除群成员
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addOrRemoveGroupUser(TokenUserInfoDto tokenUserInfoDto, String groupId, String contactIds, Integer opType) {
        GroupInfo groupInfo = groupInfoMapper.selectByGroupId(groupId);
        //1. 判断当前用户是否是群主,只有群主才能添加或移除群成员
        if (null == groupInfo || !groupInfo.getGroupOwnerId().equals(tokenUserInfoDto.getUserId())) {
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
        String[] contactIdList = contactIds.split(",");
        for (String contactId : contactIdList) {
            if (Constants.ZERO.equals(opType)) {//退出群组
                //不在这里直接调用leaveGroup,而选择通过使用service调用,是防止事务失效，因为只有在spring管理的类中调用的service方法才会加入事务
                groupInfoService.leaveGroup(contactId, groupId, MessageTypeEnum.REMOVE_GROUP);
            } else {//添加群员
                userContactService.addContact(contactId, null, groupId, UserContactTypeEnum.GROUP.getType(), null);
            }
        }
    }
}